package fieldmaps.files;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.NoSuchElementException;

import org.apache.log4j.Logger;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Polygon;

import fieldmaps.database.DatabaseRasterMap;
import fieldmaps.types.RasterMapInfo;

public class SaveRasterMapToFile {
	private String mapName;
	private String outputFile;
	private DatabaseRasterMap dbMap;
	
	private static Logger LOGGER = Logger.getLogger(SaveRasterMapToFile.class);
	
	public SaveRasterMapToFile(String mapName, String outputFile) {
		if (mapName == null || outputFile == null || mapName.isEmpty() || outputFile.isEmpty()) {
			throw new IllegalArgumentException();
		}
		this.mapName = mapName.trim();
		this.outputFile = outputFile.trim();
	}

	public void saveMap() throws IOException {
		this.dbMap = DatabaseRasterMap.loadMap(mapName);
		RasterMapInfo header = this.dbMap.getMapInfo();
		saveHeader (header, this.outputFile + ".hdr");
		saveData (this.outputFile + ".bil");
		LOGGER.info("Map successfully saved!");
	}

	private void saveData(String fileName) throws IOException {
		FileOutputStream file = new FileOutputStream(new File(fileName));
		RasterMapInfo mapInfo = this.dbMap.getMapInfo();
		byte[] bytes = new byte[mapInfo.getNbits() / 8];
		Integer[][] rasterMatrix = new Integer[mapInfo.getNrows()][mapInfo.getNcols()];
		Integer value;
	
		for (int i = 0; i < mapInfo.getNrows(); i++) {
			for (int j = 0; j < mapInfo.getNcols(); j++) {
				rasterMatrix[i][j] = mapInfo.getNodata();
			}
		}
		
		Polygon polygon;
		this.dbMap.startCellIteration();
		try {
			Integer rowIndex, colIndex;
			while ((polygon = this.dbMap.getNextCell()) != null) {
				Coordinate c = getCenterCoordinate(polygon);
				rowIndex = (int) (Math.round((mapInfo.getUlymap() - c.y) / mapInfo.getYdim()));
				colIndex = (int) (Math.round((c.x - mapInfo.getUlxmap()) / mapInfo.getXdim()));
				rasterMatrix[rowIndex][colIndex] = (Integer) polygon.getUserData();
			}
		} catch (NoSuchElementException e) {

		}
		this.dbMap.resetCellIteration();

		for (int i = 0; i < mapInfo.getNrows(); i++) {
			for (int j = 0; j < mapInfo.getNcols(); j++) {
				value = rasterMatrix[i][j];
				int c = 0;
				for (int k = bytes.length-1; k >= 0; k--) {
					bytes[c++] = (byte)(value & 0x000000FF);
					value >>= k * 8;
				}
				file.write(bytes);
				file.flush();
			}
		}
		
		file.flush();
		file.close();
	}
	
	private Coordinate getCenterCoordinate(Polygon polygon) {
		Coordinate c = new Coordinate();
		Coordinate[] polygonCoordinates = polygon.getCoordinates();
		c.x = (polygonCoordinates[1].x + polygonCoordinates[0].x)/2.0;
		c.y = (polygonCoordinates[2].y + polygonCoordinates[1].y)/2.0;
		return c;
	}

	private void saveHeader(RasterMapInfo header, String file) throws IOException {
		BufferedWriter bw = new BufferedWriter(new FileWriter(new File(file)));
		
		bw.write("BYTEORDER\t" + header.getByteOrder() + "\n");
		bw.write("LAYOUT\t" + header.getLayout() + "\n");
		bw.write("NROWS\t" + header.getNrows() + "\n");
		bw.write("NCOLS\t" + header.getNcols() + "\n");
		bw.write("NBANDS\t" + header.getNbands() + "\n");
		bw.write("NBITS\t" + header.getNbits() + "\n");
		bw.write("BANDROWBYTES\t" + header.getBandrowbytes() + "\n");
		bw.write("TOTALROWBYTES\t" + header.getTotalrowbytes() + "\n");
		bw.write("BANDGAPBYTES\t" + header.getBandgapbytes() + "\n");
		bw.write("NODATA\t" + header.getNodata() + "\n");
		bw.write("ULXMAP\t" + header.getUlxmap() + "\n");
		bw.write("ULYMAP\t" + header.getUlymap() + "\n");
		bw.write("XDIM\t" + header.getXdim() + "\n");
		bw.write("YDIM\t" + header.getYdim() + "\n");
		
		bw.close();
	}

}
